#ifndef _core_dispatch_static_dispatch_hpp_
#define _core_dispatch_static_dispatch_hpp_

/** \file static_dispatcher.hpp
 *  \author Adrian Schweizer
 *  \created  $Sa 18 Aug 03:48:01 pm CEST 2007 schwadri@SchwadriComp.local$
 *  \modified $Sa 06 Okt 04:13:03 pm CEST 2007 schwadri@SchwadriLaptop$
 */

#include "limits.hpp"
#include "util.hpp"
#include "exception.hpp"
//FIXME:#include "type_lookup/binary_search.hpp"
#include "type_lookup/switch.hpp"
#include "invoker.hpp"

//#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

namespace core {

    /** \brief Various generic dispatching utilities
     *
     *  As of now there is only the static_dispatcher. but eventually a dynamic counterpart will be provided.
     */
    namespace dispatch {

        /** \brief a static dispatcher that maps a integral value supplied at runtime to a type
         *
         *  which has been statically bound to a sp
         *  \par Template Parameter Description
         *
         *  - Signature
         *  - Functor
         *  - Actions
         *  - Key
         *  - KeyValidator
         *  - KeyRouter
         *  - TypeLookupImpl
         *
         *
         *  \par Example
         *  for an example of how to use the dispatcher look at the ActionDispatcher
         */
        template<typename Signature,
                 typename Functor,
                 typename Actions,
                 typename Key=int,
                 typename KeyValidator=util::always_true<Key>,
                 typename KeyRouter=util::default_router<Key>,
                 typename TypeLookupImpl=type_lookup::switch_<Actions> >
            class static_dispatcher
            {
            public:
                typedef Key                                                 key;
                typedef KeyValidator                                        validator;
                typedef KeyRouter                                           router;
                typedef static_dispatcher<Signature,Functor,Actions,Key,
                                   KeyValidator,KeyRouter,
                                   TypeLookupImpl>                          type;

                typedef Actions actions;
                typedef action_invoker<Signature,Functor&,Key,TypeLookupImpl>       invoker;
                typedef action_invoker<Signature,Functor,Key,TypeLookupImpl>		const_invoker;

                static_dispatcher(  const validator& validate= validator(),
                                    const router& route= router())
                :   m_validate(validate),
                    m_route(route)
                { }

                template<class InputKey>
                    const_invoker operator[](InputKey k)
                    {
                        if(m_validate(k))
                            return const_invoker(m_route(k),Functor());
                        throw invalid_key<Key>(k);
                    }

                template<class InputKey>
                    invoker operator()(InputKey k, Functor & f)
                    {
                        if(m_validate(k))
                            return invoker(m_route(k),f);
                        throw invalid_key<Key>(k);
                    }
            private:
                validator   m_validate;
                router      m_route;
            };

        #define CORE_DISPATCHER_TYPE(x) \
            (x)

        #define CORE_DETAIL_VECTOR_TYPE_FORWARD_DECL(r,data,TYPE)   \
                class TYPE;

        #define CORE_DISPATCHER_TYPE_VECTOR(TYPES,NAME)                         \
            BOOST_PP_SEQ_FOR_EACH(CORE_DETAIL_VECTOR_TYPE_FORWARD_DECL, ,TYPES) \
            typedef boost::mpl::BOOST_PP_CAT(vector,BOOST_PP_SEQ_SIZE(TYPES))<  \
            BOOST_PP_SEQ_ENUM(TYPES) > NAME;

        #define CORE_DISPATCHER_TYPE_TUPLE(x,y) \
            ((x)(y))

        #define CORE_DETAIL_MAP_TYPE_FORWARD_DECL(r,data,KEY_TYPE)   \
                struct BOOST_PP_SEQ_ELEM(1, KEY_TYPE);

        #define CORE_DETAIL_MAP_MAKE_PAIR(r,state,KEY_TYPE)   \
            BOOST_PP_COMMA_IF(state) boost::mpl::pair<boost::mpl::int_<BOOST_PP_SEQ_ELEM(0, KEY_TYPE)>,BOOST_PP_SEQ_ELEM(1, KEY_TYPE)>

        #define CORE_ACTION_TYPE_MAP_TEMPLATE_PARAMS(TYPES,NAME,SEQSIZE)          \
           CORE_DETAIL_MAP_MAKE_PAIR(,0,BOOST_PP_SEQ_ELEM(0,TYPES))               \
           BOOST_PP_SEQ_FOR_EACH(CORE_DETAIL_MAP_MAKE_PAIR, 1,BOOST_PP_SEQ_TAIL(TYPES))

        #define CORE_ACTION_TYPE_MAP_FORWARD_DECLS(TYPES,NAME,SEQSIZE)            \
            BOOST_PP_SEQ_FOR_EACH(CORE_DETAIL_MAP_TYPE_FORWARD_DECL, ,TYPES)

        #define CORE_NOTHING_3(TYPES,NAME,SEQSIZE)

        #define CORE_DISPATCHER_TYPE_MAP_IMPL_I(TYPES,NAME,SEQSIZE)                   \
            BOOST_PP_IF(SEQSIZE, CORE_ACTION_TYPE_MAP_FORWARD_DECLS,CORE_NOTHING_3)(TYPES,NAME,SEQSIZE)  \
            typedef boost::mpl::BOOST_PP_CAT(map,SEQSIZE)<                          \
            BOOST_PP_IF(SEQSIZE, CORE_ACTION_TYPE_MAP_TEMPLATE_PARAMS,CORE_NOTHING_3)(TYPES,NAME,SEQSIZE)  \
            > NAME;

        #define CORE_DISPATCHER_TYPE_MAP(TYPES,NAME)                            \
            CORE_DISPATCHER_TYPE_MAP_IMPL_I(TYPES,NAME,BOOST_PP_SEQ_SIZE(TYPES))

    } // namespace dispatch

} // namespace core


#endif // _core_dispatch_static_dispatch_hpp_
